#include "CargarDatos.h"
int cant=0;
float error= 0.00000000001;

//0,1  10,
//0,01  50,
//0,001  81,
//0,0001  123,
//0,00001  174,
//0,000001  188,
//0,0000001  188

int cargarParam(FILE* datos)
{
    char buffer[1024]=" ";
    char temp = getc(datos);
    int i = 0;
    while(!(temp == ' ' || temp == '\n'))
    {
//cout<<temp<<" ";
        buffer[i] = temp;
        temp = getc(datos);
        i++;
    }
    //cout<<atoi(buffer)<<" ";
    return atoi(buffer);
}


Matriz crearMatrizK(int n,int* coeficientes)
{
    ofstream pepe;
    pepe.open("./matriz.txt",ios::app);

    Matriz K(n,n);

    K.set(1,1,(float)(- coeficientes[1] - coeficientes[2]));
    K.set(1,2,(float)(coeficientes[2]));

    for(int i=2; i<n; i++)
    {
        K.set(i,i, (float)(-coeficientes[i] - coeficientes[i+1]));
        K.set(i,i+1, (float)(coeficientes[i+1]));
        K.set(i,i-1, (float)(coeficientes[i-1]));
    }

    K.set(n,n,(float)(-coeficientes[n]));
    K.set(n,n-1,(float)(coeficientes[n-1]));

    return K;
}


Matriz crearMatrizM(int n, int m0, int ml, int mp, int* livianos, int* pesados)
{

    ofstream pepe;
    pepe.open("./matriz.txt",ios::app);
    Matriz M(n,n);

    for(int i=1; i<=n; i++)     M.set(i,i, (float)(m0 + livianos[i]*ml));


    for(int i=1; i<=n; i++)     M.set(i,i, (float)(M.get(i,i) + pesados[i]*mp));

    return M;
}


void haceLaMagia(int n,int m0,int ml,int mp,int* pesados,int* livianos,int* coeficientes)
{

    ofstream pepa;
    pepa.open("./estadisticas.txt",ios::app);


    ofstream pepe;
    pepe.open("./matriz.txt",ios::app);

    Matriz K =  crearMatrizK(n,coeficientes);
//    pepe<<"MATRIZ K"<<endl;
    // K.print(10);
//    K.trasponer();
//    pepe<<"MATRIZ Kt"<<endl;
    //  K.print(10);

    cout<<"Ceando la Matriz M"<<endl;
    Matriz M = crearMatrizM(n,m0,ml,mp, livianos, pesados);
    pepe<<"MATRIZ M"<<endl;
//    M.print(10);

    cout<<"Ceando la Matriz M-1"<<endl;
    M.invertir();
    pepe<<"MATRIZ M-1"<<endl;
//    M.print(15);

    cout<<"Ceando la Matriz A = M-1 * K"<<endl;
    pepe<<"MATRIZ M-1 * K = A"<<endl;
    Matriz A = M.multiplicar(K);
//    A.print(12);

    cout<<"Arrancando Algoritmo QR"<<endl;
    int i =0;
    float promedio=1;
    while(fabs(promedio)>error)

    {
        i++;
        promedio = A.get(1,1);
        Matriz R = A;
        Matriz Q = calcularQRRotaciones(R);
        A = R.multiplicar(Q);
        promedio -= A.get(1,1);
    }
    cout<<endl<< "Matriz A despues de "<<i<<" iteraciones"<<endl<<endl;

    cout<<endl<<"Los Autovalores: "<<endl;
    pepe<<endl<< "Matriz A despues de "<<i<<" iteraciones"<<endl<<endl;

    A.print(10);
    pepe<<"________________________________________________________________________________________________________________________________________"<<endl<<endl;
    float autovalores[n+1];
///Imprimir Autovalores
    pepa<<cant<<"\t";
    for(int i=1; i<=n; i++)
    {
        if(A.get(i,i)>0)
        {
            cout<<endl<<endl<<"ERROR!!!! "<<A.get(i,i)<<" DEBERIA SER NEGATIVO!!"<<endl<<endl;
            exit(-1);
        }
        autovalores[i]= sqrt(-A.get(i,i));
        cout<<autovalores[i]<<" ";
        pepa<<setprecision(8)<<setw(11)<<autovalores[i]<<" ";
    }
    pepa<<"\t  \t";


///Imprimir Autos livianos y pesados


    for(int i=1; i<=n; i++)        pepa<<setprecision(3)<<setw(4)<<livianos[i];
    pepa<<"\t  \t";
    for(int i=1; i<=n; i++)        pepa<<setprecision(3)<<setw(4)<<pesados[i];

    pepa<<endl;
    cout<<endl<<endl;
    bool pisosSeguros[n+1];

    estaSeguro(n, autovalores,pisosSeguros);
    cout<<"Pisos Seguros: "<< endl;
    for(int i=1; i<=n; i++) cout<<pisosSeguros[i]<<" ";
    cout<<endl<<endl;

    if(!estaSeguro(n, autovalores,pisosSeguros))
    {
        cout<<"Cant de movimientos: "<<cant++<<endl;
        reacomodar3(n,livianos,pesados,pisosSeguros);    ///HEURISTICAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA
        haceLaMagia(n, m0, ml, mp, pesados, livianos, coeficientes);
    }
    else
    {
        cout<<endl<<endl<<"EL EDIFICIO ESTA SEGURO LA PUTA MADRE!!!"<<endl<<endl;
        cout<<"Livianos: "<<endl;
        for(int i =1 ; i<=n; i++)cout<<setprecision(3)<<setw(4)<<livianos[i]<<" ";
        cout<<endl<<endl;
        cout<<"Pesados: "<<endl;
        for(int i =1 ; i<=n; i++)cout<<setprecision(3)<<setw(4)<<pesados[i]<<" ";
        cout<<endl<<endl;
        cout<<"Cant de movimientos: "<<cant<<endl<<endl;
    }
}


bool estaSeguro(int n, float* autovalores, bool* pisosSeguros)
{
    bool res = true;
    for(int i=1; i<=n; i++)
    {
        pisosSeguros[i] = fabs(autovalores[i]-3) > 0.3;
        res = res && pisosSeguros[i];
    }
    cout<<"Edificio seguro?: "<< res<<endl;
    return res;
}


void reacomodar1(int n, int* livianos,int* pesados,bool* pisosSeguros) ///Mando 1L y 1P a cada otro piso que este seguro
{
    for(int i=1; i<=n; i++)
    {
        if(!pisosSeguros[i])
        {
            for(int j=1; j<=n; j++)
            {
                //cout<<pisosSeguros[j]<<" "<< pesados[i]<<" "<<livianos[i]<<" "<<(pisosSeguros[j] && (pesados[i]>0 || livianos[i]>0)) <<endl;
                if(pisosSeguros[j] && (pesados[i]>0 || livianos[i]>0))
                {
                    livianos[i]--;
                    livianos[j]++;
                    pesados[i]--;
                    pesados[j]++;
                    return;
                }
            }
        }
    }
    cout<<endl<<"CON ESTE METODO NO HAY SOLUCION!!"<<endl<<endl;
    exit(-1);
}

void reacomodar2(int n, int* livianos,int* pesados,bool* pisosSeguros) ///Desalojo primero los pesados y despues los livianos
{
    for(int i=1; i<=n; i++)
    {
        if(!pisosSeguros[i])
        {
            for(int j=1; j<=n; j++)
            {
                if(pisosSeguros[j] && (pesados[i]>0 || livianos[i]>0))
                {

                    if(pesados[i]==0)
                    {
                        livianos[i]--;
                        livianos[j]++;
                    }
                    else
                    {
                        pesados[i]--;
                        pesados[j]++;
                    }
                    return;
                }
            }
        }
    }
    cout<<endl<<"CON ESTE METODO NO HAY SOLUCION!!"<<endl<<endl;
    exit(-1);
}

void reacomodar3(int n, int* livianos,int* pesados,bool* pisosSeguros) ///Agrego al piso primero los pesados y despues los livianos
{
    for(int i=1; i<=n; i++)
    {
        if(!pisosSeguros[i])
        {
            for(int j=1; j<=n; j++)
            {
                if(pisosSeguros[j] && (pesados[j]>0 || livianos[j]>0))
                {

                    if(pesados[j]==0)
                    {
                        livianos[j]--;
                        livianos[i]++;
                    }
                    else
                    {
                        pesados[j]--;
                        pesados[i]++;
                    }
                    return;
                }
            }
        }
    }
    cout<<endl<<"CON ESTE METODO NO HAY SOLUCION!!"<<endl<<endl;
    exit(-1);
}

void reacomodar4(int n, int* livianos,int* pesados,bool* pisosSeguros) ///Mando 1L y 1P a cada otro piso que este seguro
{
    for(int i=1; i<=n; i++)
    {
        if(!pisosSeguros[i])
        {
            if(pesados[i]==0)
            {
                cout<<endl<<"CON ESTE METODO NO HAY SOLUCION!!"<<endl<<endl;
                exit(-1);
            }
            for(int j=1; j<=n; j++)
            {
                if(pisosSeguros[j] && (pesados[i]>0 || livianos[i]>0))
                {
                    livianos[j]++;
                    livianos[i]--;
                    pesados[j]++;
                    pesados[i]--;
                }
            }
            return;
        }
    }
}

void haceTodaLaMagia(char* archivo)
{
    remove("./matriz.txt");
    remove("./estadisticas.txt");
    ofstream pepa;
    pepa.open("./estadisticas.txt",ios::app);

    pepa<<"Paso#| \t AUTOVALORES \t \t \t \t \t \t \t \t \t \t \t \t |\t#Autos livianos por piso |\t  #Autos pesados por piso"<<endl<<endl;


    FILE* datos = fopen(archivo, "r");
    cout<<endl<<"LLEGO HASTA ACA "<< archivo<<endl;
    int n = cargarParam(datos);
    int m0 = cargarParam(datos);
    int ml = cargarParam(datos);
    int mp = cargarParam(datos);
    int pesados[n+1], livianos[n+1], coeficientes[n+1];
    cout<<n<<" "<<m0<<" "<<ml<<" "<<mp<<" "<<endl;


    for(int i=1; i<=n; i++)        coeficientes[i] = cargarParam(datos);

    for(int i=1; i<=n; i++)        livianos[i] = cargarParam(datos);

    for(int i=1; i<=n; i++)        pesados[i] = cargarParam(datos);

    haceLaMagia(n, m0, ml, mp, pesados, livianos, coeficientes);



}


//    Matriz A(3,3);
//
//    A.set(1,1,1);A.set(1,2,3);A.set(1,3,3);
//    A.set(2,1,-3);A.set(2,2,-5);A.set(2,3,-3);
//    A.set(3,1,3);A.set(3,2,3);A.set(3,3,1);
